package com.qixiaobao.common.utils.oss;


import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import com.qixiaobao.common.config.SupplyConfig;
import com.qixiaobao.common.utils.file.FileUtils;
import com.qixiaobao.common.utils.uuid.IdUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * Oss统一工具类
 *
 * @author BUER
 */
@Component
public class OssUtil {

    @Autowired
    private OssField ossField;
    private static OssUtil INSTANCE;
    OSS ossClient;

    @PostConstruct
    public void init() {
        INSTANCE = this;
        ossClient = new OSSClientBuilder().build(ossField.getEndpoint(), ossField.getAccessKeyId(), ossField.getAccessKeySecret());
    }

    public static OssUtil ins() {
        if (INSTANCE == null) {
            INSTANCE = new OssUtil();
        }

        return INSTANCE;
    }

    // 初始化构造OSS
    private OssUtil() {

    }

    /**
     * 上传图片到OSS
     *
     * @param objectName  文件名，带除上传bucket以外的文件夹路径
     * @param inputStream 数据
     */
    public void uploadFile(String objectName, InputStream inputStream) {
        while (objectName.indexOf("/") == 0) {
            objectName = objectName.substring(1);
        }
        ossClient.putObject(ossField.getBucketName(), objectName, inputStream);
    }

    /**
     * @param file
     * @return java.lang.String
     * @Description 上传文件，返回url
     * @Author yangxm
     * @Date 2024/12/5 16:18
     */
    public String uploadFile(MultipartFile file) throws IOException {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("文件不能为空");
        }
        // 生成唯一的文件名
        String fileName = IdUtils.fastSimpleUUID() + "-" + file.getOriginalFilename();
        // 创建PutObjectRequest对象
        PutObjectRequest putObjectRequest = new PutObjectRequest(ossField.getBucketName(), fileName, file.getInputStream());
        // 上传文件
        ossClient.putObject(putObjectRequest);
        // 返回文件的URL
        return "https://" + ossField.getBucketName() + "." + ossField.getEndpoint().replace("https://", "") + "/" + fileName;
    }

    /**
     * 下载文件到本地
     *
     * @param objectName
     * @return
     */
    public String downloadFile(String objectName) {
        String fullPath = SupplyConfig.getProfile() + FileUtils.getPath();
        String filePath = "";
        File file = new File(fullPath);
        if (!file.exists()) {
            file.mkdirs();
        }
        //判断保存文件名是否加后缀
        if (objectName.contains(".")) {
            //指定文件保存名称
            filePath = fullPath + objectName.substring(objectName.lastIndexOf("/") + 1);
            File targetFile = new File(filePath);
            if (targetFile.exists()) {
                filePath = fullPath + UUID.randomUUID().toString().replaceAll("-", "") + objectName.substring(objectName.lastIndexOf("."));
            }
        }
        try {
            ossClient.getObject(new GetObjectRequest(ossField.getBucketName(), objectName), new File(filePath));
        } catch (OSSException e) {
            // OSS在查找不到某对象时，会抛出ErrorCode为“NoSuchKey”的OSSException，而不是返回null
            if (e.getErrorCode().contains("NoSuchKey")) {
                System.out.println("找不到OSS文件：" + objectName);

            } else {
                e.printStackTrace();
            }
        }

        return filePath;
    }

    /**
     * 流式下载文件
     * </p>
     *
     * @param objectName 文件名，带除上传bucket以外的文件夹路径
     * @param fileName   下载后文件的名称
     */
    public void downloadFileByReader(String fileName, String objectName, HttpServletResponse response) throws
            IOException {
        // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
        OSSObject ossObject = ossClient.getObject(ossField.getBucketName(), objectName);

        response.setHeader("Content-Disposition", "attachment;filename=".concat(new String(fileName.getBytes
                ("GB2312"), StandardCharsets.ISO_8859_1)));
        OutputStream outputStream = response.getOutputStream();
        // 读取文件内容。
        BufferedInputStream is = new BufferedInputStream(ossObject.getObjectContent());

        byte[] buffBytes = new byte[1024];

        int read;
        while ((read = is.read(buffBytes)) != -1) {
            outputStream.write(buffBytes, 0, read);
        }

        outputStream.flush();
        outputStream.close();
        is.close();
    }

    /**
     * 删除OSS中的单个文件文件
     *
     * @param objectName 文件夹路径+文件名称
     */
    public void deleteFile(String objectName) {
        // 删除文件。
        if (objectName != null && objectName.length() > 0) {
            while (objectName.indexOf("/") == 0) {
                objectName = objectName.substring(1);
            }
            // 判断文件是否存在。
            boolean found = ossClient.doesObjectExist(ossField.getBucketName(), objectName);
            if (found) {
                ossClient.deleteObject(ossField.getBucketName(), objectName);
            }
        }
    }

    /**
     * 删除OSS文件夹中的同一文件夹下的所有文件
     *
     * @param contents 文件夹路径
     */
    public void deleteFiles(String contents) {
        if (StringUtils.isEmpty(contents)) {
            return;
        }
        if (!contents.endsWith("/")) {
            contents = contents + "/";
        }

        // 构造ListObjectsRequest请求
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest(ossField.getBucketName());
        // "/" 为文件夹的分隔符
        listObjectsRequest.setDelimiter("/");
        // 列出contents目录下的所有文件和文件夹
        listObjectsRequest.setPrefix(contents);
        ObjectListing listing = ossClient.listObjects(listObjectsRequest);

        //OSSobjectSummary下包含目录下所有的文件，不包含子目录
        for (OSSObjectSummary objectSummary : listing.getObjectSummaries()) {
            deleteFile(objectSummary.getKey());
        }

        for (String item : listing.getCommonPrefixes()) {
            if (StringUtils.isEmpty(item)) {
                continue;
            }
            deleteFiles(item);
        }
    }

    /**
     * 获取文件访问地址(设置URL过期时间为配置文件中的时间)
     * </p>
     *
     * @param objectName 文件夹路径+文件名称
     * @return URL 图片访问绝对路径
     */
    public String getFileUrl(String objectName) {
        String urlStr = null;
        if (objectName != null && objectName.length() > 0) {

            while (objectName.indexOf("/") == 0) {
                objectName = objectName.substring(1);
            }
            boolean found = ossClient.doesObjectExist(ossField.getBucketName(), objectName);
            if (!found) {
                return null;
            }
            // 设置URL过期时间为1小时
            Date expiration = new Date(System.currentTimeMillis() + Long.parseLong(ossField.getExpireTime()));
            // 创建URL
            URL url = ossClient.generatePresignedUrl(ossField.getBucketName(), objectName, expiration);
            if (url != null) {
                urlStr = url.toString().substring(0, url.toString().indexOf("?"));
            }
        }
        return urlStr;
    }

    /**
     * 获取文件访问地址(设置URL过期时间为1小时)
     * </p>
     *
     * @param contents 文件夹路径
     * @return URL 图片访问绝对路径
     */
    public List<String> listFileUrls(String contents) {
        if (StringUtils.isEmpty(contents)) {
            return new ArrayList<>();
        }
        if (!contents.endsWith("/")) {
            contents = contents + "/";
        }

        List<String> listFileUrl = new ArrayList<>();

        // 构造ListObjectsRequest请求
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest(ossField.getBucketName());
        // "/" 为文件夹的分隔符
        listObjectsRequest.setDelimiter("/");
        // 列出contents目录下的所有文件和文件夹
        listObjectsRequest.setPrefix(contents);
        ObjectListing listing = ossClient.listObjects(listObjectsRequest);

        for (String item : listing.getCommonPrefixes()) {
            if (StringUtils.isEmpty(item)) {
                continue;
            }
            List<String> fileUrls = listFileUrls(item);
            if (fileUrls != null && fileUrls.size() > 0) {
                listFileUrl.addAll(fileUrls);
            }
        }

        //OSSobjectSummary下包含目录下所有的文件，不包含子目录
        for (OSSObjectSummary objectSummary : listing.getObjectSummaries()) {
            String url = getFileUrl(objectSummary.getKey());
            if (StringUtils.isEmpty(url)) {
                continue;
            }
            listFileUrl.add(url);
        }

        return listFileUrl;
    }

    /**
     * 通过文件名判断并获取OSS服务文件上传时文件的contentType
     *
     * @param fileName 文件名
     * @return 文件的contentType
     */
    public static String getContentType(String fileName) {
        String FilenameExtension = fileName.substring(fileName.lastIndexOf("."));
        if (FilenameExtension.equalsIgnoreCase(".bmp")) {
            return "application/x-bmp";
        }
        if (FilenameExtension.equalsIgnoreCase(".gif")) {
            return "image/gif";
        }
        if (FilenameExtension.equalsIgnoreCase(".jpeg") ||
                FilenameExtension.equalsIgnoreCase(".jpg") ||
                FilenameExtension.equalsIgnoreCase(".png")) {
            return "image/jpeg";
        }
        if (FilenameExtension.equalsIgnoreCase(".html")) {
            return "text/html";
        }
        if (FilenameExtension.equalsIgnoreCase(".txt")) {
            return "text/plain";
        }
        if (FilenameExtension.equalsIgnoreCase(".vsd")) {
            return "application/vnd.visio";
        }
        if (FilenameExtension.equalsIgnoreCase(".pptx") ||
                FilenameExtension.equalsIgnoreCase(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (FilenameExtension.equalsIgnoreCase(".docx") ||
                FilenameExtension.equalsIgnoreCase(".doc")) {
            return "application/msword";
        }
        if (FilenameExtension.equalsIgnoreCase(".xla") ||
                FilenameExtension.equalsIgnoreCase(".xlc") ||
                FilenameExtension.equalsIgnoreCase(".xlm") ||
                FilenameExtension.equalsIgnoreCase(".xls") ||
                FilenameExtension.equalsIgnoreCase(".xlt") ||
                FilenameExtension.equalsIgnoreCase(".xlw")) {
            return "application/vnd.ms-excel";
        }
        if (FilenameExtension.equalsIgnoreCase(".xml")) {
            return "text/xml";
        }
        if (FilenameExtension.equalsIgnoreCase(".pdf")) {
            return "application/pdf";
        }
        if (FilenameExtension.equalsIgnoreCase(".zip")) {
            return "application/zip";
        }
        if (FilenameExtension.equalsIgnoreCase(".tar")) {
            return "application/x-tar";
        }
        if (FilenameExtension.equalsIgnoreCase(".avi")) {
            return "video/avi";
        }
        if (FilenameExtension.equalsIgnoreCase(".mp4")) {
            return "video/mpeg4";
        }
        if (FilenameExtension.equalsIgnoreCase(".mp3")) {
            return "audio/mp3";
        }
        if (FilenameExtension.equalsIgnoreCase(".mp2")) {
            return "audio/mp2";
        }
        return "application/octet-stream";
    }
}
